package mail.fetch.qq;

import mail.exception.MailDetailException;
import mail.exception.ParseMailException;
import mail.util.PublicMethod;
import mail.util.CookieParser;
import mail.util.RegexSearcher;
import mail.util.StatusCode;

import java.io.IOException;
import java.net.CookieManager;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import static com.han.http.util.Print.printlnErr;

/**
 * @author: Hanjiafeng
 * @date: Created in 14:32 2019/1/25
 * @desc: 收件箱
 */
class Inbox11 {

    /**
     * 定义请求发送对象
     */
    private HttpClient.Builder baseClientBuilder;

    /**
     * 定义请求Builder
     */
    private HttpRequest.Builder baseRequestBuilder;

    /**
     * 登录传入的CookieManager
     */
    private CookieManager cookieManager;

    private boolean isDuringHalfYear = true;

    /**
     * 使用传入的CookieManager初始化类
     *
     * @param cookieManager CookieManager
     */
    Inbox11(CookieManager cookieManager) {
        this.cookieManager = cookieManager;
        //设置通用参数
        baseClientBuilder = HttpClient.newBuilder()
                .cookieHandler(cookieManager)
                //禁止自动跳转
                .followRedirects(HttpClient.Redirect.NEVER);
        //设置通用参数
        baseRequestBuilder = HttpRequest.newBuilder()
                .timeout(Duration.ofMinutes(1))
                .header("Accept", "image/webp,image/apng,image/*,*/*;q=0.8")
                .header("Accept-Encoding", "gzip, deflate, br")
                .header("Accept-Language", "zh-CN,zh;q=0.9")
                .header("DNT", "1")
                .header("Upgrade-Insecure-Requests", "1")
                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3664.3 Safari/537.36");
    }

    /**
     * 获取半年内的邮件并解析
     *
     * @return 半年内的邮件
     */
    List<QqMailEntity> getMailListDuringHalfYear() {
        //邮件容器
        List<QqMailEntity> duringHalfYearMailList = new ArrayList<>();
        //当前邮件页码
        int currentPageIndex = 0;
        boolean isLastPage = false;
        while (isDuringHalfYear && !isLastPage) {
            try {
                //获取指定页码邮件列表并解析
                String page = getMailListByPageIndex(currentPageIndex);
                List<QqMailEntity> qqMailEntityList = parseMailList(page);
                duringHalfYearMailList.addAll(qqMailEntityList);
                isLastPage = isLastPage(page);
                //如果最后一封邮件也在180天之内,页码+1,继续获取下一页的邮件,重复判断
                if (isDuringHalfYear && !isLastPage) {
                    currentPageIndex++;
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
                break;
            }
            try {
                //休眠3秒,避免被封
                Thread.sleep(1000 * 3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return duringHalfYearMailList;
    }

    /**
     * 解析当前页面是否是最后一页,如果页面中不包含下一页按钮,判断为最后一页
     *
     * @param page 邮件页面
     * @return 是否是最后一页
     */
    private boolean isLastPage(String page) {
        String m = RegexSearcher.matchFirst(page, "<div class=\"toolbg toolbgline toolheight nowrap\" style=\"\">((?!nextpage1).)*(?=nextpage1)");
        return m.isBlank() || m.isEmpty();
    }

    /**
     * 获取邮箱列表
     *
     * @return 邮箱列表
     * @throws IOException          io
     * @throws InterruptedException in
     */
    private String getMailListByPageIndex(int pageIndex) throws IOException, InterruptedException {
        String url = "https://mail.qq.com/cgi-bin/mail_list?" +
                "sid=" + CookieParser.getSpecifiedCookie(cookieManager, "sidu") + "&" +
                "folderid=1" +
                "&folderkey=1" +
                "&page=" + pageIndex +
                "&s=inbox" +
                "&topmails=0" +
                "&showinboxtop=1" +
                "&ver=737483.0" +
                "&cachemod=maillist" +
                "&cacheage=7200" +
                "&r=";

        return PublicMethod.getTextFromUrl(baseClientBuilder.build(), baseRequestBuilder, url);
    }

    /**
     * 将邮件字符串解析成邮件实体
     *
     * @param mailListStr 邮件字符串
     * @return 邮件实体列表
     */
    private List<QqMailEntity> parseMailList(String mailListStr) {
        List<QqMailEntity> qqMailEntityList = new ArrayList<>();
        //切分所有邮件字符串
        LinkedList<String> mailStringList = RegexSearcher.match(mailListStr, "<table cellspacing=\"0\" class=\"i [MF]{1}\">((?!</table>).)*</table>");
        //挨个解析
        for (String mailString : mailStringList) {
            try {
                QqMailEntity entity = parseMail(mailString);
                qqMailEntityList.add(entity);
            } catch (ParseMailException e) {
                String errMsg = e.getMessage();
                if (errMsg.equals(StatusCode.MAIL_PARSE_EXPIRE)) {
                    break;
                }
                printlnErr("解析邮件失败," + errMsg + ":" + mailString);
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return qqMailEntityList;
    }

    /**
     * 解析单个的邮件字符串为邮件实体
     *
     * @param body 邮件字符串
     * @return 邮件实体
     */
    private QqMailEntity parseMail(String body) throws ParseMailException {
        //时间
        String millSecond = RegexSearcher.matchFirst(body, "(?<=totime=\")((?!\").)*(?=\")");
        Date date = new Date();
        try {
            long mailMills = Long.valueOf(millSecond);
            date = new Date(mailMills);
        } catch (NumberFormatException e) {
            printlnErr("未获取到发送时间戳,默认使用当前时间戳:" + e.getMessage());
        }
        //邮件日期是否在半年之内
        isDuringHalfYear = PublicMethod.isDuringHalfYear(date);
        if (!isDuringHalfYear) {
            throw new ParseMailException(StatusCode.MAIL_PARSE_EXPIRE);
        }
        //主题
        String subject = RegexSearcher.matchFirst(body, "(?<=<u tabindex=\"0\"((?!>).){0,50}>)((?!</u>).)*(?=</u>)");
        //如果主题中不包含账单关键字,返回异常
        if (!subject.contains(StatusCode.MAIL_CREDIT_KEY_WORD)) {
            throw new ParseMailException(StatusCode.MAIL_PARSE_NOT_CREDIT);
        }
        //邮件id
        String mailId = RegexSearcher.matchFirst(body, "(?<= mailid=\")((?!\").)*(?=\")");
        if (mailId.isEmpty() || mailId.isBlank()) {
            throw new ParseMailException(StatusCode.MAIL_PARSE_NO_ID);
        }
        //发件人
        String sender = RegexSearcher.matchFirst(body, "(?<=n=\")((?!\").)*(?=\")");
        //发件地址
        String senderAddr = RegexSearcher.matchFirst(body, "(?<=e=\")((?!\").)*(?=\")");
        //获取邮件内容
        String content = getMailDetail(mailId);

        return new QqMailEntity(mailId, subject, sender, senderAddr, null, null, date, content);
    }

    /**
     * 获取具体的邮件内容
     *
     * @param mailId 邮件id
     * @return 邮件内容
     * @throws MailDetailException 获取邮件详情失败
     */
    private String getMailDetail(String mailId) throws MailDetailException {
        String url = "https://mail.qq.com/cgi-bin/readmail?" +
                "folderid=1" +
                "&folderkey=1" +
                "&t=readmail" +
                "&mailid=" + mailId +
                "&mode=pre" +
                "&maxage=3600" +
                "&base=11.93" +
                "&ver=13586" +
                "&sid=" + CookieParser.getSpecifiedCookie(cookieManager, "sidu");
        String detail;
        try {
            detail = PublicMethod.getTextFromUrl(baseClientBuilder.build(), baseRequestBuilder, url);
        } catch (IOException | InterruptedException e) {
            throw new MailDetailException("获取邮件详情失败");
        }
        return detail;
    }
}
